{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "553b8c7c-29cf-445d-9168-2aaad522fc13",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "原始数据信息:\n",
      "==================================================\n",
      "样本数量: 178个\n",
      "特征数量: 13个\n",
      "\n",
      "PCA分析结果 - 特征值大小排列:\n",
      "==================================================\n",
      "主成分      特征值             方差解释率        累积方差        \n",
      "--------------------------------------------------\n",
      "PC1       99201.790       0.998        0.998       \n",
      "PC2       172.535         0.002        1.000       \n",
      "PC3       9.438           0.000        1.000       \n",
      "PC4       4.991           0.000        1.000       \n",
      "PC5       1.229           0.000        1.000       \n",
      "PC6       0.841           0.000        1.000       \n",
      "PC7       0.279           0.000        1.000       \n",
      "PC8       0.151           0.000        1.000       \n",
      "PC9       0.112           0.000        1.000       \n",
      "PC10      0.072           0.000        1.000       \n",
      "PC11      0.038           0.000        1.000       \n",
      "PC12      0.021           0.000        1.000       \n",
      "PC13      0.008           0.000        1.000       \n",
      "\n",
      "降维决策:\n",
      "==============================\n",
      "累积方差超过90%所需的主成分数量: 1\n",
      "前1个主成分累积方差: 0.998 (99.8%)\n",
      "决策: 从13维降到1维\n",
      "\n",
      "降维结果:\n",
      "==============================\n",
      "新数据维度: 178个样本 × 1个特征\n",
      "\n",
      "保存降维数据:\n",
      "==============================\n",
      "降维后数据保存成功！\n"
     ]
    }
   ],
   "source": [
    "import pandas as pd\n",
    "import math\n",
    "import numpy as np\n",
    "\n",
    "\n",
    "#pandas,numpy仅用于辅助计算\n",
    "\n",
    "#加载数据\n",
    "def load_csv_data(file_path):\n",
    "    try:\n",
    "        df = pd.read_csv(file_path, header=None)\n",
    "        return df.values.tolist()\n",
    "    except Exception as e:\n",
    "        print(f\"读取CSV文件时出错: {e}\")\n",
    "        return None\n",
    "\n",
    "#pca主要流程\n",
    "def pca_optimized(X, num_components=None):\n",
    "    n = len(X)\n",
    "    p = len(X[0])\n",
    "    \n",
    "    # (1) 数据去中心化: Y = X - 1μ^T\n",
    "    μ = [sum(X[i][j] for i in range(n)) / n for j in range(p)]  # 均值向量\n",
    "    Y = []\n",
    "    for i in range(n):\n",
    "        y_i = [X[i][j] - μ[j] for j in range(p)]\n",
    "        Y.append(y_i)\n",
    "    \n",
    "    # (2) 样本协方差矩阵: S = (1/(n-1)) Y^T Y\n",
    "    S = [[0] * p for _ in range(p)]\n",
    "    for i in range(p):\n",
    "        for j in range(p):\n",
    "            for k in range(n):\n",
    "                S[i][j] += Y[k][i] * Y[k][j]\n",
    "            S[i][j] /= (n - 1)\n",
    "    \n",
    "    # (3) 使用幂法求解特征值和特征向量\n",
    "    eigenvalues = []\n",
    "    eigenvectors = []\n",
    "    S_current = S\n",
    "    \n",
    "    num_components = num_components or p\n",
    "    for _ in range(num_components):\n",
    "        # 幂法求解最大特征值和特征向量\n",
    "        w = [1.0] * p\n",
    "        norm = math.sqrt(sum(x*x for x in w))\n",
    "        w = [x/norm for x in w]\n",
    "        \n",
    "        for _ in range(1000):\n",
    "            w_new = [0] * p\n",
    "            for i in range(p):\n",
    "                for j in range(p):\n",
    "                    w_new[i] += S_current[i][j] * w[j]\n",
    "            \n",
    "            norm = math.sqrt(sum(x*x for x in w_new))\n",
    "            w_new = [x/norm for x in w_new]\n",
    "            \n",
    "            diff = sum(abs(w_new[i] - w[i]) for i in range(p))\n",
    "            if diff < 1e-8:\n",
    "                break\n",
    "            \n",
    "            w = w_new\n",
    "        \n",
    "        # 计算特征值: λ = w^T S w\n",
    "        Sw = [0] * p\n",
    "        for i in range(p):\n",
    "            for j in range(p):\n",
    "                Sw[i] += S_current[i][j] * w[j]\n",
    "        \n",
    "        λ = sum(w[i] * Sw[i] for i in range(p))\n",
    "        \n",
    "        eigenvalues.append(λ)\n",
    "        eigenvectors.append(w)\n",
    "        \n",
    "        # (4) 收缩矩阵: S_new = S - λ w w^T\n",
    "        S_new = [[0] * p for _ in range(p)]\n",
    "        for i in range(p):\n",
    "            for j in range(p):\n",
    "                S_new[i][j] = S_current[i][j] - λ * w[i] * w[j]\n",
    "        \n",
    "        S_current = S_new\n",
    "    \n",
    "    # (5) 计算贡献率\n",
    "    total_variance = sum(eigenvalues)\n",
    "    explained_variance = [λ / total_variance for λ in eigenvalues]\n",
    "    cumulative_variance = []\n",
    "    current_sum = 0\n",
    "    for ev in explained_variance:\n",
    "        current_sum += ev\n",
    "        cumulative_variance.append(current_sum)\n",
    "    \n",
    "    # (6) 主成分变换: Z = Y W_m\n",
    "    W_m = eigenvectors[:num_components]  # 变换矩阵\n",
    "    Z = []  # 主成分得分矩阵\n",
    "    for i in range(n):\n",
    "        z_i = []\n",
    "        for k in range(num_components):\n",
    "            projection = sum(Y[i][j] * W_m[k][j] for j in range(p))\n",
    "            z_i.append(projection)\n",
    "        Z.append(z_i)\n",
    "    \n",
    "    return Z, eigenvalues, eigenvectors, explained_variance, cumulative_variance, μ\n",
    "\n",
    "#保存新的\n",
    "def save_pca_results(Z, output_file=\"new_dataset.csv\"):\n",
    "    # 保存主成分得分\n",
    "    df_scores = pd.DataFrame(Z)\n",
    "    # 根据维度设置列名\n",
    "    if len(Z[0]) == 1:\n",
    "        df_scores.columns = ['PC1']\n",
    "    else:\n",
    "        df_scores.columns = [f'PC{i+1}' for i in range(len(Z[0]))]\n",
    "    \n",
    "    df_scores.to_csv(output_file, index=False)\n",
    "    return df_scores\n",
    "\n",
    "# 主程序\n",
    "if __name__ == \"__main__\":\n",
    "    # 加载数据\n",
    "    data = load_csv_data(\"dataset.csv\")\n",
    "    \n",
    "    if data is None:\n",
    "        print(\"无法加载数据\")\n",
    "        exit(1)\n",
    "    \n",
    "    n = len(data)\n",
    "    p = len(data[0])\n",
    "    \n",
    "    # 1. 首先展示原始数据特征\n",
    "    print(\"原始数据信息:\")\n",
    "    print(\"=\" * 50)\n",
    "    print(f\"样本数量: {n}个\")\n",
    "    print(f\"特征数量: {p}个\")\n",
    "    \n",
    "    # 执行PCA（计算所有13个主成分）\n",
    "    Z_all, eigenvalues, eigenvectors, explained_var, cum_var, means = pca_optimized(data, num_components=13)\n",
    "    \n",
    "    # 2. 展示特征值大小排列和累积方差\n",
    "    print(f\"\\nPCA分析结果 - 特征值大小排列:\")\n",
    "    print(\"=\" * 50)\n",
    "    print(f\"{'主成分':<8} {'特征值':<15} {'方差解释率':<12} {'累积方差':<12}\")\n",
    "    print(\"-\" * 50)\n",
    "    \n",
    "    for i, (ev, var, cum) in enumerate(zip(eigenvalues, explained_var, cum_var)):\n",
    "        print(f\"PC{i+1:<7} {ev:<15.3f} {var:<12.3f} {cum:<12.3f}\")\n",
    "    \n",
    "    # 3. 根据累积方差确定降维维度\n",
    "    print(f\"\\n降维决策:\")\n",
    "    print(\"=\" * 30)\n",
    "    \n",
    "    optimal_components = 1\n",
    "    for i, cv in enumerate(cum_var):\n",
    "        if cv >= 0.9:\n",
    "            optimal_components = i + 1\n",
    "            break\n",
    "    \n",
    "    print(f\"累积方差超过90%所需的主成分数量: {optimal_components}\")\n",
    "    print(f\"前{optimal_components}个主成分累积方差: {cum_var[optimal_components-1]:.3f} ({cum_var[optimal_components-1]*100:.1f}%)\")\n",
    "    print(f\"决策: 从{p}维降到{optimal_components}维\")\n",
    "    \n",
    "    # 4. 执行降维并保存结果\n",
    "    Z, eigenvalues, eigenvectors, explained_var, cum_var, means = pca_optimized(data, num_components=optimal_components)\n",
    "    \n",
    "    print(f\"\\n降维结果:\")\n",
    "    print(\"=\" * 30)\n",
    "    print(f\"新数据维度: {n}个样本 × {optimal_components}个特征\")\n",
    "    \n",
    "    # 5. 仅保存降维后的数据\n",
    "    print(f\"\\n保存降维数据:\")\n",
    "    print(\"=\" * 30)\n",
    "    \n",
    "    df_new = save_pca_results(Z, \"new_dataset.csv\")\n",
    "    print(\"降维后数据保存成功！\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
